package com.sihai.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;

/**
 * <code>DynamicQueryBuilder</code> 用于动态创建 {@link org.hibernate.Query} 对象
 */
public class DynamicQuery {

	private StringBuilder hql = new StringBuilder();

	public List<String> parameterNames = new ArrayList<String>();

	public List<Object> parameterValues = new ArrayList<Object>();

	public List<String> getParameterNames() {
		return parameterNames;
	}

	public List<Object> getParameterValues() {
		return parameterValues;
	}

	public DynamicQuery(String hql) {
		this.hql.append(hql);
	}

	public DynamicQuery append(String hql) {
		return append(hql, null, (String) null);
	}

	public DynamicQuery append(String hql, String[] names, Object[] values) {
		this.hql.append(" ").append(hql);
		if (names != null && values != null && names.length > 0 && values.length > 0) {
			if (names.length != values.length) {
				throw new IllegalArgumentException("name and value does not have same lenght");
			}
			for (int i = 0; i < names.length; i++) {
				String name = names[i];
				Object value = values[i];
				if (StringUtils.isNotBlank(name)) {
					parameterNames.add(name);
					parameterValues.add(value);
				}

			}
		}
		return this;
	}

	public DynamicQuery append(String hql, String name, Object value) {
		return append(hql, new String[] { name }, new Object[] { value });
	}

	public DynamicQuery appendIfNotNull(String hql, String name, Object value) {
		if (value != null) {
			return append(hql, name, value);
		}
		return this;
	}

	public DynamicQuery appendIfNotEmpty(String hql, String name, String value) {
		if (StringUtils.isNotBlank(value)) {
			return append(hql, name, StringUtils.trim(value));
		}
		return this;
	}

	public String getQueryString() {
		return this.hql.toString();
	}

	/**
	 * Apply the given name parameter to the given Query object.
	 * 
	 * @param query the Query object
	 * @param name the name of the parameter
	 * @param value the value of the parameter
	 */
	@SuppressWarnings("rawtypes")
	private void setParameter(Query query, String name, Object value) {

		if (value instanceof Collection) {
			query.setParameterList(name, (Collection) value);
		} else if (value instanceof Object[]) {
			query.setParameterList(name, (Object[]) value);
		} else {
			query.setParameter(name, value);
		}
	}

	public Query build(Session session) {
		Query query = session.createQuery(this.getQueryString());
		if (parameterNames != null && !parameterNames.isEmpty()) {
			for (int i = 0; i < parameterNames.size(); i++) {
				this.setParameter(query, parameterNames.get(i), this.parameterValues.get(i));
			}
		}
		return query;
	}
}